package me.zhengjie.utils;

import cn.hutool.core.io.BufferUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.socket.nio.NioClient;
import io.swagger.models.auth.In;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;

@Component
public class GsSocketUtils {
    private static final Logger log = LoggerFactory.getLogger(GsSocketUtils.class);

    private static String ip;
    private static Integer port;
    private static String username;
    private static String password;
    private static String huanbaoCode;

    //平台登录次数
    private static int loginCount;
    private static String loginDate;

    public static NioClient nioClient = null;
    public static byte[] returnBytes;

    public static String replyMessage;

    @Value("${guosi.ip}")
    public void setIp(String ip) {
        this.ip = ip;
    }
    @Value("${guosi.port}")
    public void setPort(String port) {
        this.port = Integer.valueOf(port);
    }
    @Value("${guosi.username}")
    public void setUsername(String username) {
        this.username = username;
    }
    @Value("${guosi.password}")
    public void setPassword(String password) {
        this.password = password;
    }
    @Value("${guosi.huanbao-code}")
    public void setHuanbaoCode(String huanbaoCode) {
        this.huanbaoCode = huanbaoCode;
    }


    public static synchronized boolean startClient() throws InterruptedException {
        nioClient = new NioClient(ip, port);
        nioClient.setChannelHandler((sc)->{
            ByteBuffer readBuffer = ByteBuffer.allocate(1024);
            //从channel读数据到缓冲区
            int readBytes = sc.read(readBuffer);
            if (readBytes > 0) {
                //Flips this buffer.  The limit is set to the current position and then
                // the position is set to zero，就是表示要从起始位置开始读取数据
                readBuffer.flip();
                //returns the number of elements between the current position and the  limit.
                // 要读取的字节长度
                byte[] bytes = new byte[readBuffer.remaining()];
                //将缓冲区的数据读到bytes数组
                readBuffer.get(bytes);
                returnBytes = bytes;
                replyMessage = binaryToHexString(bytes);
                log.info("国四通讯receive: {}", replyMessage);
            } else if (readBytes < 0) {
                sc.close();
            }
        });
        nioClient.listen();

        //发送平台登录消息
        //起始符
        String strStart = "##";
        byte[] bytesStart = strStart.getBytes();
        //命令单元
        String hexMingling = "07 FE";  //平台登录
        byte[] bytesMingling = hexStringToByteArray(hexMingling);
        //机械环保代码
        String strHuanbaoCode = huanbaoCode;
        byte[] bytesHuanbaoCode = strHuanbaoCode.getBytes();
        //数据加密方式
        String hexJiaMi = "01";
        byte[] bytesJiaMi = hexStringToByteArray(hexJiaMi);

        //数据单元
        byte[] bytesData = getLoginData();

        //数据单元长度
        int dataLength = bytesData.length;
        byte[] bytesDataLength = intToWord(dataLength);
        //BBC校验码的数据
        byte[] bytesDataA = byteMerger(bytesMingling,bytesHuanbaoCode,bytesJiaMi,bytesDataLength,bytesData);
        byte[] bytesBbc = getBCC(bytesDataA);
        byte[] bytesFinal = byteMerger(bytesStart,bytesDataA,bytesBbc);
        nioClient.write(BufferUtil.create(bytesFinal));
        log.info("国四平台登录: {}", binaryToHexString(bytesFinal));

        Thread.currentThread().sleep(500);//延迟1秒，检查登录是否成功

        if(replyMessage.length()>16){
            if(replyMessage.substring(9,11).equals("01")){
                return true;
            }else
                return false;
        }else{
            return false;
        }

    }
    /**
     * 获取登录消息单元
     * @return
     */
    private static byte[] getLoginData(){
        //时间
        byte[] bytesTime = getCurrTime();
        //流水码
        int liushuima = getLoginCount();
        byte[] bytesLiushuima = intToWord(liushuima);
        //用户名
        String account = username;
        byte[] bytesAccount = account.getBytes();
        //平台密码
        byte[] bytesPassword = password.getBytes();
        //加密规则
        String hexJiaMi = "01";
        byte[] bytesJiaMi = hexStringToByteArray(hexJiaMi);
        //数据单元
        byte[] bytesData = byteMerger(bytesTime,bytesLiushuima,bytesAccount,bytesPassword,bytesJiaMi);
        return bytesData;
    }

    /**
     * 获取平台登录计数器，以天为单位重计
     * @return
     */
    public static int getLoginCount(){
        DateFormat dateInstance = DateFormat.getDateInstance();
        String currDate = dateInstance.format(new Date());
        if(currDate.equals(loginDate)){
            loginCount = loginCount + 1;
        }else{
            loginCount = 1;
            loginDate = currDate;
        }
        return loginCount;
    }


    public static NioClient getNioClient() throws InterruptedException {
        if(nioClient == null ){
            startClient();
        }
        if(!nioClient.getChannel().isConnected()){
            startClient();
        }
        return  nioClient;
    }

    public static void sendBytes(byte[] bytes) throws InterruptedException {
        log.info("国四通讯send: {}", binaryToHexString(bytes));
        try{
            getNioClient().write(BufferUtil.create(bytes));
        }catch (IORuntimeException ex){
            //异常断开重送
            startClient();
            getNioClient().write(BufferUtil.create(bytes));
        }
    }

    public static void close(){
        try {
            nioClient.close();
        }catch (Exception e){
            log.info("国四通讯关闭错误: {}", e.getMessage());
        }
    }

    public static boolean getChannelConnected(){
        return  nioClient.getChannel().isConnected();
    }
    /**
     * 获取当前日期的字符串
     * @return
     */
    public static String getCurrDateStr(){
        DateFormat dateInstance = DateFormat.getDateInstance();
        String currDate = dateInstance.format(new Date());
        return  currDate;
    }
    /**
     * 获取当前时间
     * @return
     */
    public static byte[] getCurrTime(){
        byte[] bytesTime = new byte[6];
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, -1);
        Integer year = Integer.valueOf(Integer.valueOf(calendar.get(Calendar.YEAR)).toString().substring(2,4));
        bytesTime[0] = year.byteValue();
        bytesTime[1] = Integer.valueOf(calendar.get(Calendar.MONTH)+1).byteValue();
        bytesTime[2] = Integer.valueOf(calendar.get(Calendar.DATE)).byteValue();
        bytesTime[3] = Integer.valueOf(calendar.get(Calendar.HOUR_OF_DAY)).byteValue();
        bytesTime[4] = Integer.valueOf(calendar.get(Calendar.MINUTE)).byteValue();
        bytesTime[5] = Integer.valueOf(calendar.get(Calendar.SECOND)).byteValue();
        return  bytesTime;
    }
    /**
     * 将int转为 BYTE
     * @return
     */
    public static byte[] intToDword(int i){
        Integer j = Integer.valueOf(i);
        String temp = Integer.toHexString(j);
        String hexStr = "";
        if(temp.length()==1){
            hexStr =  "00 00 00 0" + temp;
        }else if(temp.length()==2){
            hexStr =  "00 00 00 " + temp;
        }else if(temp.length()==3){
            hexStr =  "00 00 0" + temp.substring(0,1) + " " + temp.substring(1,3);
        }else if(temp.length()==4){
            hexStr =  "00 00 " + temp.substring(0,2) + " " + temp.substring(2,4);
        }else if(temp.length()==5){
            hexStr =  "00 0" + temp.substring(0,1) + " " + temp.substring(1,3) + " " + temp.substring(3,5);
        }else if(temp.length()==6){
            hexStr =  "00 " + temp.substring(0,2) + " " + temp.substring(2,4) + " " + temp.substring(4,6);
        }else if(temp.length()==7){
            hexStr =  "0" + temp.substring(0,1) + " " + temp.substring(1,3) + " " + temp.substring(3,5) + " " + temp.substring(5,7);
        }else if(temp.length()==8){
            hexStr =  temp.substring(0,2) + " " + temp.substring(2,4) + " " + temp.substring(4,6) + " " + temp.substring(6,8);
        }else{
            hexStr =  temp.substring(temp.length()-8,temp.length()-6) + " " + temp.substring(temp.length()-6,temp.length()-4) + " " + temp.substring(temp.length()-4,temp.length()-2) + " " + temp.substring(temp.length()-2,temp.length());
        }
        return hexStringToByteArray(hexStr);
    }
    /**
     * 将int转为 word
     *
     * @return
     */
    public static byte[] intToWord(int i){
        Integer j = Integer.valueOf(i);
        String temp = Integer.toHexString(j);
        String hexStr = "";
        if(temp.length()==1){
            hexStr =  "00 0" + temp;
        }else if(temp.length()==2){
            hexStr =  "00 " + temp;
        }else if(temp.length()==3){
            hexStr =  "0" + temp.substring(0,1) + " " + temp.substring(1,3);
        }else if(temp.length()==4){
            hexStr =  temp.substring(0,2) + " " + temp.substring(2,4);
        }else{
            hexStr =  temp.substring(temp.length()-4,temp.length()-2) + " " + temp.substring(temp.length()-2,temp.length());
        }
        return hexStringToByteArray(hexStr);
    }

    /**
     * 将int转为 BYTE
     * @return
     */
    public static byte[] intToByte(int i){
        Integer j = Integer.valueOf(i);
        String temp = Integer.toHexString(j);
        String hexStr = "";
        if(temp.length()==1){
            hexStr =  "0" + temp;
        }else if(temp.length()==2){
            hexStr =  temp;
        }else{
            hexStr =  temp.substring(temp.length()-2,temp.length());
        }
        return hexStringToByteArray(hexStr);
    }


    /**
     * 获取BBC校验码
     * @return
     */
    public static byte[] getBCC(byte[] data) {
        String ret = "";
        byte BCC[]= new byte[1];
        for(int i=0;i<data.length;i++)
        {
            BCC[0]=(byte) (BCC[0] ^ data[i]);
        }
        String hex = Integer.toHexString(BCC[0] & 0xFF);
        if (hex.length() == 1) {
            hex = '0' + hex;
        }
        ret += hex.toUpperCase();
        return hexStringToByteArray(ret);
    }

    /**
     * 合并byte数组
     * @return
     */
    public static byte[] byteMerger(byte[] bt1, byte[] bt2){
        byte[] bt3 = new byte[bt1.length+bt2.length];
        System.arraycopy(bt1, 0, bt3, 0, bt1.length);
        System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
        return bt3;
    }
    /**
     * 合并byte数组
     * @return
     */
    public static byte[] byteMerger(byte[]... bts){
        int length = 0;
        for (byte[] bt : bts) {
            length = length + bt.length;
//            System.out.println(BinaryToHexString(bt));
        }

        byte[] btResult = new byte[length];
        int currlength = 0;
        for (byte[] bt : bts) {
            System.arraycopy(bt, 0, btResult, currlength, bt.length);
            currlength = currlength + bt.length;
//            System.out.println(currlength);
//            System.out.println(BinaryToHexString(bt));
        }

//        System.out.println(BinaryToHexString(btResult));
        return btResult;
    }
    /**
     * 将字节数组转换成十六进制的字符串
     * @return
     */
    public static String binaryToHexString(byte[] bytes) {
        String hexStr = "0123456789ABCDEF";
        String result = "";
        String hex = "";
        for (byte b : bytes) {
            hex = String.valueOf(hexStr.charAt((b & 0xF0) >> 4));
            hex += String.valueOf(hexStr.charAt(b & 0x0F));
            result += hex + " ";
        }
        return result;
    }

    /**
     * 16进制表示的字符串转换为字节数组
     * @param hexString 16进制表示的字符串
     * @return byte[] 字节数组
     */
    public static byte[] hexStringToByteArray(String hexString) {
        hexString = hexString.replaceAll(" ", "");
        int len = hexString.length();
        byte[] bytes = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            // 两位一组，表示一个字节,把这样表示的16进制字符串，还原成一个字节
            bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
                    .digit(hexString.charAt(i + 1), 16));
        }
        return bytes;
    }
}
